package com.blelibrary;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.CountDownTimer;

import com.utils.LogUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

/**
 * 蓝牙4.0串口数据交互（透传）
 */
public class BleOperate {
    int TIME_OUT = 10000;//蓝牙UUID服务匹配时间

    private BleOperate() {
    }

    public static BleOperate getInstance() {
        return BleOperateHelp.instance;
    }

    static class BleOperateHelp {
        static final BleOperate instance = new BleOperate();
    }

    private final static UUID UUID_NOTIFY =
            UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");
    private final static UUID UUID_SERVICE =
            UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
    private ArrayList<BluetoothGatt> connectionQueue = new ArrayList<BluetoothGatt>();
    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    private String mBluetoothDeviceAddress;
    private Context mContext;
    private String deviceAddress;
    private Map<String, SearchBleMacResultListener> listenerMap = new HashMap<String, SearchBleMacResultListener>();

    /**
     * 蓝牙的初始化
     *
     * @param c
     * @return 蓝牙是否可用
     */
    public boolean initialize(Context c) {
        this.mContext = c;
        if (mBluetoothManager == null) {
            mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
            if (mBluetoothManager == null) {
                return false;
            }
        }
        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            return false;
        }
        return true;
    }

    /**
     * 连接指定的mac地址
     *
     * @param address        蓝牙地址
     * @param searchListener 搜索结果接口
     */
    public void connectBleDeviceByMac(String address, SearchBleMacResultListener searchListener) {
        deviceAddress = address;
        listenerMap.put(address, searchListener);
        if (mBluetoothManager == null) {
            throw new InstantiationError("BluetoothManager 对象初始化错误");
        }
        //开启蓝牙
        mBluetoothAdapter.enable();
        boolean flag = false;
        //是否已连接该设备
        for (int i = 0; i < connectionQueue.size(); i++) {
            BluetoothGatt gatt = connectionQueue.get(i);
            if (gatt.getDevice().getAddress().equals(address)) {
                searchListener.hasConnected();
                flag = true;
                return;
            }
        }
        if (address != null && !flag) {
            timer.start();
            scanLeDevice(true);
        }
    }

    /**
     * 重置监听器
     *
     * @param bleMacAddress
     * @return
     */
    public void setBleResultListener(String bleMacAddress, SearchBleMacResultListener listener) {
        listenerMap.put(bleMacAddress, listener);
    }

    private CountDownTimer timer = new CountDownTimer(TIME_OUT, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
            SearchBleMacResultListener searchBleMacResultListener = listenerMap.get(deviceAddress);
            if (searchBleMacResultListener != null) {
                searchBleMacResultListener.progress(millisUntilFinished);
                LogUtils.e("倒数计时:" + millisUntilFinished / 1000);
            }
        }

        @Override
        public void onFinish() {
            SearchBleMacResultListener searchBleMacResultListener = listenerMap.get(deviceAddress);

            if (searchBleMacResultListener != null) {
                searchBleMacResultListener.timeOut();
                LogUtils.e("连接超时");
                mBluetoothAdapter.stopLeScan(mLeScanCallback);

            }
        }
    };

    private void scanLeDevice(final boolean enable) {
        if (enable) {

            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            LogUtils.e("停止扫描");
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }

    /**
     * 搜索回调，搜索到设备时触发
     */
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
            LogUtils.e("蓝牙设备" + device.getName() + "蓝牙地址：" + device.getAddress());
            if (device.getAddress().equals(deviceAddress)) {
                scanLeDevice(false);
                SearchBleMacResultListener searchListener = listenerMap.get(deviceAddress);
                if (connect(deviceAddress) && searchListener != null) {
                    searchListener.searchResult(true);
                } else if (searchListener != null) {
                    searchListener.searchResult(false);
                } else {
                    LogUtils.e("SearchBleMacResultListener  为null");
                }
            }
        }
    };

    /**
     * 连接ble备
     *
     * @param address
     * @return
     */
    public boolean connect(final String address) {

        if (mBluetoothAdapter == null || address == null) {
            LogUtils.e("mBluetoothAdapter 没有实例化 或者没有指定MAC地址");
            return false;
        }
        BluetoothGatt mBluetoothGatt = null;
        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
                && mBluetoothGatt != null) {
            LogUtils.e("尝试使用一个存在的 mBluetoothGatt 进行连接");
            if (mBluetoothGatt.connect()) {
                return true;
            } else {
                return false;
            }
        }

        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        if (device == null) {
            LogUtils.e("设备没有发现 ，不能进行连接");
            return false;
        }
        mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
        LogUtils.e("尝试创建一个新的连接");
        mBluetoothDeviceAddress = address;

        //连接成功后添加到 已连接设备列表
        if (checkGatt(mBluetoothGatt)) {
            connectionQueue.add(mBluetoothGatt);
            LogUtils.e("mBluetoothGatt 保存到  list");
        }
        return true;
    }

    /**
     * 检查设备是否已在 已连接设备数组 中
     *
     * @param bluetoothGatt
     * @return
     */
    private boolean checkGatt(BluetoothGatt bluetoothGatt) {
        if (!connectionQueue.isEmpty()) {
            for (BluetoothGatt btg : connectionQueue) {
                if (btg.equals(bluetoothGatt)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 连接回调
     */
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                LogUtils.e("开启发现GATT服务:" + gatt.discoverServices());
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                LogUtils.e("断开GATT服务:" + gatt.discoverServices());//发现服务
                String address = gatt.getDevice().getAddress();
                LogUtils.e("断开蓝牙地址：" + address);
                SearchBleMacResultListener searchBleMacResultListener = listenerMap.get(address);
                if (searchBleMacResultListener != null) {
                    searchBleMacResultListener.disconect(address);
                    LogUtils.e("断开通知前台");
                }
                synchronized (connectionQueue){
                    Iterator iter = connectionQueue.iterator();
                    while (iter.hasNext()) {
                        BluetoothGatt ga = (BluetoothGatt) iter.next();
                        if (ga == gatt) {
                            iter.remove();
                            LogUtils.e("相应的服务已经移除");
                            break;
                        }
                    }
                }

            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                LogUtils.e("GATT连接成功");
                //查找对应服务
                findService(gatt);
            } else {
                LogUtils.e("服务不能发现: " + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic,
                                         int status) {
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            BluetoothGattCharacteristic characteristic1 = characteristic;
            LogUtils.e("串口返回值:" + characteristic1.getValue());
            String address = gatt.getDevice().getAddress();
            LogUtils.e("蓝牙地址：" + address);
            SearchBleMacResultListener searchBleMacResultListener = listenerMap.get(address);
            if (searchBleMacResultListener != null) {
                searchBleMacResultListener.onResultReceive(characteristic1.getValue());
                LogUtils.e("分发前台");
            }
        }

    };


    /**
     * 查找设备对应服务
     * @param gatt
     */
    public void findService(BluetoothGatt gatt) {
        List<BluetoothGattService> gattServices = gatt.getServices();
        for (BluetoothGattService gattService : gattServices) {
            if (gattService.getUuid().toString().equalsIgnoreCase(UUID_SERVICE.toString())) {
                List<BluetoothGattCharacteristic> gattCharacteristics =
                        gattService.getCharacteristics();
                LogUtils.e("Service的 UUID已匹配");
                SearchBleMacResultListener searchListener = listenerMap.get(gatt.getDevice().getAddress());

                if (searchListener != null) {
                    searchListener.findUUIDService();
                }
                for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                    if (gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_NOTIFY.toString())) {
                        LogUtils.e("NOTIFY UUID已匹配");
                        if (searchListener != null) {
                            searchListener.findUUIDNotify();
                        }
                        timer.cancel();
                        setCharacteristicNotification(gattCharacteristic, true);
                        return;
                    }
                }
            }
        }
    }

    /**
     * 打开notify
     *
     * @param characteristic
     * @param enabled
     */
    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if (mBluetoothAdapter == null || connectionQueue.isEmpty()) {
            LogUtils.e("BluetoothAdapter 没有初始化 或者 list中没有 BluetoothGatt 对象");
            return;
        }
        for (BluetoothGatt bluetoothGatt : connectionQueue) {
            bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        }
    }

    /**
     * 发送数据
     *
     * @param address
     * @param inits
     */
    public void writeCharacteristic(String address, byte[] inits) {
        if (connectionQueue != null && connectionQueue.size() > 0) {
            for (BluetoothGatt gatt : connectionQueue) {
                if (gatt.getDevice().getAddress().equals(address)) {
                    if (gatt == null) {
                        LogUtils.e("BluetoothGatt  为空,不能写入数据");
                        return;
                    }
                    BluetoothGattService gattService = gatt.getService(UUID
                            .fromString(UUID_SERVICE.toString()));
                    if (gattService == null) {
                        LogUtils.e("BluetoothGattService 为空,不能写入数据");
                        return;
                    }
                    BluetoothGattCharacteristic characteristic = gattService
                            .getCharacteristic(UUID
                                    .fromString(UUID_NOTIFY.toString()));
                    if (characteristic == null) {
                        LogUtils.e("BluetoothGattCharacteristic is null,不能写入数据");
                        return;
                    }
                    characteristic.setValue(inits);
                    LogUtils.e("写入数据:");
                    LogUtils.e("是否发送成功 :" + gatt.writeCharacteristic(characteristic));
                }
            }
        }
    }

    /**
     * 发送数据
     */
    public boolean writeCharacteristic(String address, String value) {
        if (connectionQueue != null && connectionQueue.size() > 0) {
            for (BluetoothGatt gatt : connectionQueue) {
                if (gatt.getDevice().getAddress().equals(address)) {
                    if (gatt == null) {
                        LogUtils.e("BluetoothGatt  为空,不能写入数据");
                        return false;
                    }
                    BluetoothGattService gattService = gatt.getService(UUID
                            .fromString(UUID_SERVICE.toString()));
                    if (gattService == null) {
                        LogUtils.e("BluetoothGattService 为空,不能写入数据");
                        return false;
                    }
                    BluetoothGattCharacteristic characteristic = gattService
                            .getCharacteristic(UUID
                                    .fromString(UUID_NOTIFY.toString()));
                    if (characteristic == null) {
                        LogUtils.e("BluetoothGattCharacteristic is null,不能写入数据");
                        return false;
                    }
                    characteristic.setValue(value);
                    LogUtils.e("开始写入数据:");
                    boolean result = gatt.writeCharacteristic(characteristic);
                    LogUtils.e("是否发送成功 :" + result);
                    return result;
                }
            }
        }
        return false;
    }

    /**
     * 断开所有设备连接
     */
    public void disconnect() {
        if (timer != null) {
            timer.cancel();
        }
        if (mBluetoothAdapter == null || connectionQueue.isEmpty()) {
            LogUtils.e("BluetoothAdapter not initialized");
            return;
        }
//       Set<String>   keySet= listenerMap.keySet();
//      Iterator   iterator=  keySet.iterator();
//        while (iterator.hasNext()){
//           listenerMap.remove(iterator.next());
//        }
        synchronized (connectionQueue) {
            for (BluetoothGatt bluetoothGatt : connectionQueue) {
                bluetoothGatt.disconnect();
                bluetoothGatt.close();
            }
            listenerMap.clear();
            connectionQueue.clear();
        }
    }

    /**
     * 断开指定设备连接
     *
     * @param address
     */
    public boolean disconnect(String address) {
        if (mBluetoothAdapter == null || connectionQueue.isEmpty()) {
            LogUtils.e("BluetoothAdapter not initialized");
            return false;
        }

        synchronized (connectionQueue) {
            Iterator iter = connectionQueue.iterator();
            while (iter.hasNext()) {
                BluetoothGatt gatt = (BluetoothGatt) iter.next();
                if (gatt.getDevice().getAddress().equals(address)) {
                    gatt.disconnect();
                    gatt.close();
                    iter.remove();
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 关闭指定设备的bluetoothgatt
     *
     * @param address
     */
    public void close(String address) {
        if (connectionQueue.isEmpty()) {
            return;
        }
        listClose(address);
    }

    //关闭所有设备的Bluetoothgatt
    public void close() {
        if (connectionQueue.isEmpty()) {
            return;
        }
        listClose(null);
    }

    private synchronized void listClose(String address) {
        if (!connectionQueue.isEmpty()) {
            if (address != null) {
                for (final BluetoothGatt bluetoothGatt : connectionQueue) {
                    if (bluetoothGatt.getDevice().getAddress().equals(address)) {
                        bluetoothGatt.close();

                        new Thread(new Runnable() {
                            public void run() {
                                try {
                                    Thread.sleep(250);
                                    connectionQueue.remove(bluetoothGatt);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                }
            } else {
                for (BluetoothGatt bluetoothGatt : connectionQueue) {
                    bluetoothGatt.close();
                }
                connectionQueue.clear();
            }
        }
    }

}
